package com.gitee.wsl.common.chart.adapter

import com.gitee.wsl.api.SelectAbleItem
import com.gitee.wsl.common.chart.animation.AbstractChartAnimation
import com.gitee.wsl.common.chart.animation.NoAnimation
import com.gitee.wsl.common.chart.api.ChartDatasetChangeListenerContain
import com.gitee.wsl.common.chart.listener.ChartDatasetChangeListener
import com.gitee.wsl.common.chart.listener.ChartSelectListener
import com.gitee.wsl.common.chart.listener.click.PositionRecord

import com.gitee.wsl.ext.list.notInIndex
import com.gitee.wsl.ext.list.setAll
import timber.log.Timber
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

interface SelectItemChartAdapter<T> :
    com.gitee.wsl.common.ui.api.SelectListenerContainer<ChartSelectListener<T>>,
    ChartDatasetChangeListenerContain<ChartDatasetChangeListener<T>>

open class AbstractSelectItemChartAdapter<T:SelectAbleItem,P: PositionRecord>: com.gitee.wsl.common.ui.api.ObjectSelectAble<List<T>>,
    com.gitee.wsl.common.ui.api.TouchCheckAble,SelectItemChartAdapter<T> {

    //数据源
    val dataset = mutableListOf<T>()

    val noSelectDataSet : List<T>
        get() {
            return if(!isTouched())
                dataset
            else
                dataset.filter { !isSelectItem(it)  }
        }

    //数据对应位置
    val recordset = mutableListOf<P>()

    //当前选择对像
    val selectItemList =  mutableListOf<T>()

    var isRecordSetInited = false

    var dataAnimation: AbstractChartAnimation<T> = NoAnimation<T>()

    fun startDataAnimation(callBack: com.gitee.wsl.common.ui.api.InvalidateAble){
        dataAnimation.animateFrom(0f,dataset,callBack)
    }

     override val selectListenerList:MutableList<ChartSelectListener<T>> = mutableListOf()

     override val datasetChangeListenerList :MutableList<ChartDatasetChangeListener<T>> = mutableListOf()

     fun setDataSource(newDataSource:List<T>){
         if(dataset.isEmpty() && newDataSource.isEmpty()) return

         val oldList=dataset.toList()
         dataset.setAll(newDataSource)
         datasetChangeListenerList.forEach {
             it.onDatasetChanged(oldList,newDataSource)
         }

         initState()
     }

     private fun initState(){
         recordset.clear()
         selectItemList.clear()
         isRecordSetInited=false
         dataset.filter {
             it.isSelected
         }.forEach {
             selectItemList.add(it)
         }
     }

     override fun selectObject(x: Float, y: Float): List<T>? {
         val select= mutableListOf<T>()
         recordset.forEach {
             if(it.compareRange(x,y)) select.add(dataset[it.dataID])
         }
         Timber.d("selectObject touchX:$x,touchY:$y,select:${select.size}")
         return select
     }

     fun isSelectItem(item:T):Boolean{
         if(item.isSelected || !isTouched()) return false
         return selectItemList[0] == item
     }

     fun selectItem(item:T):Boolean{
         if(isSelectItem(item)) return false
         item.isSelected = true
         selectItemList.setAll(listOf(item))
         return true
     }

     fun selectItemUseIndex(index:Int):Boolean{
         if(dataset.notInIndex(index)) return false
         return selectItem(dataset[index])
     }

     override fun isTouched():Boolean  = selectItemList.isNotEmpty()

     override fun callTouchListener(){
         if(!isTouched()) return
         selectListenerList.forEach {
             it.onClick(selectItemList[0])
         }
     }

     override fun checkTouch(touchX:Float, touchY:Float):Boolean{
         clearTouch()
         selectObject(touchX,touchY)?.let { list ->
             selectItemList.setAll(list)
             list.forEach {
                 it.isSelected = true
             }
         }
         return isTouched()
     }

     override fun clearTouch(){
         selectItemList.clear()
         dataset.forEach {
             it.isSelected = false
         }
     }

    fun addRecordItem(record:P){
        recordset.add(record)
    }

 }

 class DataSource<T:SelectAbleItem,P: PositionRecord>(val adapter:AbstractSelectItemChartAdapter<T,P>):
     ReadWriteProperty<Any, List<T>>{
     override fun getValue(thisRef: Any, property: KProperty<*>): List<T> {
         return adapter.dataset
     }

     override fun setValue(thisRef: Any, property: KProperty<*>, value: List<T>) {
         adapter.setDataSource(value)
     }
 }